// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-12-05

package scheduler

import (
	"encoding/json"
	"sync"
	"time"
)

var (
	responsePool = &sync.Pool{
		New: func() any {
			return &response{}
		},
	}
	responseTime = time.Unix(0, 0)
)

type (
	Response interface {
		End() Response
		GetBody() []byte
		GetDuration() time.Duration
		GetEndTime() time.Time
		GetError() error
		GetStartTime() time.Time
		HasError() bool
		Release()
		SetBody(body []byte)
		SetError(err error)
		String() string
	}

	response struct {
		Body      []byte    `json:"Body,omitempty"`
		EndTime   time.Time `json:"EndTime,omitempty"`
		Err       error     `json:"Err,omitempty"`
		StartTime time.Time `json:"StartTime,omitempty"`
	}
)

func NewResponse() Response { return responsePool.Get().(*response).acquirer() }

// + Getter

func (o *response) GetBody() []byte            { return o.Body }
func (o *response) GetError() error            { return o.Err }
func (o *response) GetDuration() time.Duration { return o.EndTime.Sub(o.StartTime) }
func (o *response) GetEndTime() time.Time      { return o.EndTime }
func (o *response) GetStartTime() time.Time    { return o.StartTime }
func (o *response) HasError() bool             { return o.Err != nil }

// + Setter

func (o *response) SetBody(body []byte) { o.Body = body }
func (o *response) SetError(err error)  { o.Err = err }

// + Common

func (o *response) End() Response {
	o.EndTime = time.Now()

	if o.Body == nil && o.Err != nil {
		o.Body = []byte(o.Err.Error())
	}
	return o
}

func (o *response) Release() {
	o.releaser()
}

func (o *response) String() string {
	if buf, err := json.Marshal(o); err == nil {
		return string(buf)
	}
	return ""
}

// + Access

func (o *response) acquirer() *response {
	o.StartTime = time.Now()
	return o
}

func (o *response) releaser() {
	o.Body, o.Err = nil, nil
	o.EndTime, o.StartTime = responseTime, responseTime
}
